package dolphin.mt521.cam.ac.uk;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;

import org.apache.commons.io.IOUtils;

import android.util.Log;

public class Encode {

    private static float sampleRate = 32000f;   //sample rate, must be (power of 2)*1000
    private static int msecs = 64;            //duration of each tone, must be power of 2
    private static int chunkSize = msecs*((int)sampleRate)/1000;    //the size of one block of encoded data in bytes
    private static int spacing = 30;
    
    public static float getSampleRate() {
        return sampleRate;
    }
    public static int getMsecs() {
        return msecs;
    }
    public static int getChunkSize() {
        return chunkSize;
    }
    public static int getSpacing() {
        return spacing;
    }
    
    public static byte[] buffer(int freq) {
        byte[] sineWave = new byte[((int)sampleRate)*2*msecs/1000];
        
        short temp;
        ByteBuffer buffer = ByteBuffer.allocate(2);
        
        float freqRatio = sampleRate/freq; //allow for mismatch in sample rate and frequency (both measured in Hz)
        for (int i=0; i<sineWave.length; i+=2) {
            double angle = (i*Math.PI)/freqRatio; //was 2pi but am dividing by 2 due to doubled array size
            temp = (short)(Math.sin(angle) * 32767.0);
            buffer.putShort(0,temp);
            sineWave[i] = buffer.get(1); //PCM is little endian so second byte first
            sineWave[i+1] = buffer.get(0);
            //sine of an angle gives ~1->1, we want a number in the range ~32768->32767 (16 bits), so multiply by
            //that to use all byte values.
        }
        return sineWave;
    }

    /*multiple tones on top of each other
    public static byte[] bufferChord(String[] freqs, int msecs) {
        byte[] sineWave = new byte[(int)sampleRate*msecs/1000];
        for (int n=0; n<freqs.length; n++) {
            float freqRatio = sampleRate/Integer.parseInt(freqs[n]);
            for (int i=0; i<sineWave.length; i++) {
                double angle = i/freqRatio * 2.0 * Math.PI;
                sineWave[i] += (byte)(Math.sin(angle) * (127.0/freqs.length));
            }
        }
        return sineWave;
    }*/
    
    public static void encode(byte[] data) {
        int seqLen = data.length; 
        byte[][] complete = new byte[seqLen+1][]; //extra chunk containing silence for better playback
        byte[] wave = null;
        int freq;
        for (int i=0; i<seqLen; i++) {
            freq = data[i]>0 ? (int)data[i] : ((int)data[i])+256; //make all frequencies positive
            wave = Encode.buffer((freq*spacing)+300);
            complete[i] = wave;
        }
        complete[seqLen]=Encode.buffer(0);
        
        int freqNum = complete.length;
        int sineLength = complete[0].length;
        byte[] superBuffer = new byte[sineLength*freqNum];
        for (int i=0; i<freqNum; i++) {
            for (int j=0; j<sineLength; j++) {
                superBuffer[(sineLength*i)+j] = complete[i][j];
            }
        }
        Output.play(superBuffer);
    }
    
    public static byte[] convertToBytes(File file) {
        byte[] byteFile = null;
        FileInputStream fis;
        try {
            fis = new FileInputStream(file);
            byteFile = IOUtils.toByteArray(fis);
        }
        catch (FileNotFoundException e) {
            Log.e("Encode.convertToBytes","File Not Found");
        }
        catch (IOException e) {
            Log.e("Encode.convertToBytes","IOException");
        }
        return byteFile;
    }
    
}
